/*
 * Copyright 2003-2005 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

#include "TypeMeta.h"

#include "MetaArray.h"

#include "MetaSequence.h"

#include "../common/BigEndianUnsignedByte.h"

type_name meta_sequence_name = { "meta.sequence" };

int meta_sequence_bind( type_element * element, type_definition * definition )
{
	meta_sequence * ms = (meta_sequence *) element;
	int x;
	int rc;
	
	rc = type_object_bind( &element->object, definition->library, &meta_sequence_name );
	if ( rc != TYPE_OK ) return rc;

	rc = type_element_bind( element, definition );
	if ( rc != TYPE_OK ) return rc;

	for ( x=0 ; x < ms->size; x++ )
	{
		rc = ms->objects[x]->element.bind( &(ms->objects[x]->element), definition );
		if ( rc != TYPE_OK ) return rc;
	}
	
	return TYPE_OK;
}

void meta_sequence_init( meta_sequence * ms, meta_expression ** objects, int size )
{
	type_element_init( &(ms->expression.element), &meta_sequence_bind );
	meta_expression_init( &(ms->expression), &meta_sequence_do_read, &meta_sequence_do_write );
	
	ms->objects = objects;
	ms->size = size;
}

void * meta_sequence_construct( type_list * objects, type_map * map )
{
	type_item * objItem = type_list_head( objects );
	type_list * sequence = type_item_get_list( objItem );
	
	meta_sequence * ms = (meta_sequence *) type_malloc( sizeof( meta_sequence ) );

	int size = type_list_size( sequence );
	type_item * item = type_list_head( sequence );
	
	meta_expression ** seqObjects = (meta_expression **) type_malloc( size * sizeof( meta_expression * ) );
	
	int x = 0;
	while ( item != 0 )
	{
		seqObjects[x] = (meta_expression * ) type_item_get_ptr( item );
		item = type_item_next( item );
		x++;
	}

	meta_sequence_init( ms, seqObjects, size );
	return ms;
}

void meta_sequence_clear( meta_sequence * ms )
{
	type_free( ms->objects );
}

meta_expression * meta_sequence_get_element( meta_sequence * ms, int x )
{
	return ms->objects[x];
}

int meta_sequence_size( meta_sequence * ms )
{
	return ms->size;
}

int meta_sequence_read( type_input_stream * in, type_element * element)
{
	return type_reader_auto( in, element, &meta_sequence_construct );
}
	
int meta_sequence_write( type_output_stream * out, void * o, type_element * element )
{
	meta_sequence * ms = (meta_sequence *) o;
	int x;
	int rc;

	rc = type_output_write_named_object( out, &uint8_name, &ms->size );
	if ( rc != TYPE_OK ) return rc;
	
	for ( x=0 ; x < ms->size ; x++ )
	{
		meta_expression * o  = ms->objects[x];

		rc = type_output_write_named_object( out, &meta_expression_name, o );
		if ( rc != TYPE_OK ) return rc;
	}
	return TYPE_OK;
}


int meta_sequence_do_read( type_input_stream * in, type_element * element)
{
	meta_sequence * ms = (meta_sequence *) element;
	/* setup the top of the stack with the returned list. */
	type_list * list = type_stack_get_list(&in->stack);
	int x;
	
	/* make sure list is clear */
	type_list_init( list );
	
	if ( meta_sequence_size(ms) == 0 )
	{
		type_input_set_error( in, 10 );
		return TYPE_EOF;
	}
	
	for (  x=0; x < ms->size ; x++ )
	{
		/* get next element. */
		meta_expression * te = meta_sequence_get_element( ms, x );
		
		/* push a new element on the stack. */
		type_stack_push( &in->stack );
		
		/* read the value into the element. */
		te->doRead( in, (type_element *) te );
		
		/* remove and put on local list. */
		type_list_add_tail( list, type_stack_remove( &in->stack ) );
	}
	
	return TYPE_OK;
}


int meta_sequence_do_write( type_output_stream * out, void * o, type_element * element )
{
	type_output_set_error( out, 10 );
	return TYPE_EOF;	
}

